#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include <pci/pci.h>
#include <linux/pci.h>

#include <sys/param.h>
#include <sys/utsname.h>

/*
 gcc -o pci_test pci_test.c -l pci
*/


#define PCI_CLASSID(a)      ((a)>>16) & 0xFF
#define PCI_SUBCLASSID(a)   ((a)>>8) & 0xFF 
#define PCI_PROG_IF(a)      (a) & 0xFF
    
#define MASS_STORAGE_CONTROLLER_CLASS   0x01
#define NETWORK_CONTROLLER_CLASS        0x02
#define SERIAL_BUS_CONTROLLER_CLASS     0x0c

#define SCSI_STORAGE_CONTROLLER_SUBCLASS 0x00
#define IDE_INTERFACE_SUBCLASS           0x01

#define ETHERNET_CONTROLLER_SUBCLASS     0x00    
#define USB_CONTROLLER_SUBCLASS          0x03 

#define USB_UHCI_PROG_IF    0x0
#define USB_OHCI_PROG_IF    0x10
#define USB_EHCI_PROG_IF    0x20


void pre_test()
{
    int id = 0x000c0300;
    printf("class Id = %x\n", PCI_CLASSID(id));
    printf("sub class Id = %x\n", PCI_SUBCLASSID(id));
    printf("prog if = %x\n", PCI_PROG_IF(id));
}

int main()
{
    
    pre_test();
    
	static struct pci_access *pacc;
	struct pci_dev *dev;
	unsigned int c;
	
	pacc = pci_alloc();
	pci_init(pacc);
	pci_scan_bus(pacc);	
	for(dev=pacc->devices; dev; dev=dev->next) 
	{
		u_int8_t config[256];
		memset(config,'\0',256);
		pci_read_block(dev, 0, config, 64);
		pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES);
		c = pci_read_word(dev, PCI_CLASS_DEVICE);
		fprintf(stderr,"Found a Device (0x%02x): 0x%04x 0x%04x\n", c, dev->vendor_id, dev->device_id);
		if (c == PCI_CLASS_SERIAL_USB)
		{
			unsigned int prog;
			prog = config[PCI_CLASS_PROG];
			if (prog == 0)
			{
				fprintf(stderr, "Found USB UHCI controller\n"); 
			}
			else if (prog == 0x10)
			{
				fprintf(stderr, "Found USB OHCI controller\n"); 
			}
			else if (prog == 0x20)
			{
				fprintf(stderr, "Found USB EHCI controller\n"); 
			}
		}
	}

	return 0;
}
